package com.csx.ops.service.node;

import com.offbytwo.jenkins.JenkinsServer;
import com.offbytwo.jenkins.client.JenkinsHttpClient;
import com.offbytwo.jenkins.model.Build;
import com.offbytwo.jenkins.model.JobWithDetails;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.yh.csx.bsf.core.base.BsfException;
import com.yh.csx.bsf.core.base.Callable;
import com.yh.csx.bsf.core.util.PropertyUtils;
import com.yh.csx.bsf.core.util.StringUtils;
import lombok.*;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.*;

/**
 * 参考
 * https://www.cnblogs.com/anliven/p/13642675.html
 * https://blog.csdn.net/qq_32641153/article/details/94230465
 */
@XStreamAlias("JenkinsNode")
public class JenkinsNode extends ConfigNode {
    @Getter
    @Setter
    @XStreamAlias("App")
    private String app;
    @Getter @Setter
    @XStreamAlias("Param")
    private String param;


    @Override
    public void exec(){
        printParam(app,param);
        try {
            writeLog("jenkins job开始");
            new JenkinsProvider().exec(app,parseParam(),(log)->{writeLog(log);});
            writeLog("jenkins job完毕");
        }catch (Exception e){
            throw new StateException("jenkins job执行失败",e);
        }
    }

    private Map<String,String> parseParam(){
        var rs = new HashMap<String,String>();
        var lines = this.param.split("\n");
        for(var line:lines){
            var kv = line.split("=");
            if(kv.length==2){
                var key = StringUtils.nullToEmpty(kv[0]).trim();
                var value = StringUtils.nullToEmpty(kv[1]).trim();
                rs.put(key,value);
            }
        }
        return rs;
    }


    private class JenkinsProvider
    {
        JenkinsHttpClient client = null;
        JenkinsServer server = null;
        public JenkinsProvider(){
            try {
                client = new JenkinsHttpClient(new URI(
                        PropertyUtils.getPropertyCache("jenkins.url","")),
                        PropertyUtils.getPropertyCache("jenkins.username",""),
                        PropertyUtils.getPropertyCache("jenkins.password",""));
                server = new JenkinsServer(new URI(
                        PropertyUtils.getPropertyCache("jenkins.url","")),
                        PropertyUtils.getPropertyCache("jenkins.username",""),
                        PropertyUtils.getPropertyCache("jenkins.password",""));
            } catch (URISyntaxException e) {
                throw new BsfException(e);
            }
        }


        private void exec(String app, Map<String,String> params, Callable.Action1<String> log){
            try {
                var j = getJob(app);
                var lastMaxBuild = getMaxBuild(app);
                log.invoke("准备创建jenkins job任务");
                if(params.size()==0)
                    j.build();
                else
                    j.build(params);
                var currentMaxBuild = getMaxBuild(app);
                if(currentMaxBuild.getNumber()<lastMaxBuild.getNumber()){
                    throw new StateException("创建build失败");
                }
                log.invoke("创建jenkins job完毕,build number:"+currentMaxBuild.getNumber());
                var currentBuild = j.getBuildByNumber(currentMaxBuild.getNumber());
                var currentLog= currentBuild.details().getConsoleOutputText(0);
                log.invoke(currentLog.getConsoleLog());
                // 检测是否还有更多日志,如果是则继续循环获取
                while (currentLog.getHasMoreData()){
                    // 获取最新日志信息
                    val newLog = currentBuild.details().getConsoleOutputText(currentLog.getCurrentBufferSize());
                    // 输出最新日志
                    var newContent = newLog.getConsoleLog();
                    log.invoke(newContent);
                    currentLog = newLog;
                    // 睡眠1s
                    Thread.sleep(1000);
                }

            }catch (Exception e){
                throw new BsfException(e);
            }
        }

        private JobWithDetails getJob(String job){
            try {
                var j = server.getJob(app);
                if (j == null)
                    throw new StateException("jenkins job不存在:" + app);
                return j;
            }catch (Exception e){
                throw new BsfException(e);
            }
        }

        //获取最大build
        private Build getMaxBuild(String job){
            try {
                var max = getJob(job).getAllBuilds().stream().max(Comparator.comparing(Build::getNumber));
                return max.isPresent()?max.get():null;
            }catch (Exception e){
                throw new BsfException(e);
            }
        }
    }

    //从子节点设置对应的状态机
    public void setEngine(StateEngine engine){
        super.setEngine(engine);
    }
}
